﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using MusicWorks.Web.Logic.Views;
using MusicWorks.Web.Logic.Presenters;
using MusicWorks.Web.Logic.Helpers;
using System.IO;
using CatalogService = MusicWorks.Web.Logic.CatalogService;
using ShoppingService = MusicWorks.Web.Logic.ShoppingService.svc;

namespace MusicWorks.UnitTests.Web.Logic
{
    [TestClass]
    public class ProductPresenterTests
    {
        [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void ProductPresenter_Load_ThrowsIfIdEmpty()
        {
            var context = new Context();

            context.RaiseLoadEvent();
        }

        [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void ProductPresenter_Load_ThrowsIfProductNotFound()
        {
            var context = new Context();
            context.View.Stub(v => v.ProductId).Return("abc");
            context.View.Stub(v => v.CatalogName).Return("def");
            context.Catalog.Stub(c => c.GetProduct("ABC", "def")).Return(null);

            context.RaiseLoadEvent();
        }

        [TestMethod]
        public void ProductPresenter_Load_ReturnsProductModelWithId()
        {
            var context = new Context();
            context.View.Stub(v => v.ProductId).Return("abc");
            context.View.Stub(v => v.CatalogName).Return("def");
            context.Catalog.Stub(c => c.GetProduct("ABC", "def")).Return(new CatalogService.Product { Id = "abc" });

            context.RaiseLoadEvent();

            var product = context.View.Model;
            Assert.AreEqual("abc", product.Id);
        }

        [TestMethod]
        public void ProductPresenter_Load_ReturnsProductModelWithDisplayName()
        {
            var context = new Context();
            context.View.Stub(v => v.ProductId).Return("abc");
            context.View.Stub(v => v.CatalogName).Return("def");
            context.Catalog.Stub(c => c.GetProduct("ABC", "def")).Return(new CatalogService.Product { DisplayName = "abc" });

            context.RaiseLoadEvent();

            var product = context.View.Model;
            Assert.AreEqual("abc", product.DisplayName);
        }
        
        [TestMethod]
        public void ProductPresenter_Load_ReturnsProductModelWithDescription()
        {
            var context = new Context();
            context.View.Stub(v => v.ProductId).Return("abc");
            context.View.Stub(v => v.CatalogName).Return("def");
            context.Catalog.Stub(c => c.GetProduct("ABC", "def")).Return(new CatalogService.Product { Description = "abc" });

            context.RaiseLoadEvent();

            var product = context.View.Model;
            Assert.AreEqual("abc", product.Description);
        }

        [TestMethod]
        public void ProductPresenter_Load_ReturnsProductModelWithFormattedPrice()
        {
            var context = new Context();
            context.View.Stub(v => v.ProductId).Return("abc");
            context.View.Stub(v => v.CatalogName).Return("def");
            context.Catalog.Stub(c => c.GetProduct("ABC", "def")).Return(new CatalogService.Product { ListPrice = 10.2M });

            context.RaiseLoadEvent();

            var product = context.View.Model;
            Assert.AreEqual("$10.20", product.FormattedPrice);
        }

        [TestMethod]
        public void ProductPresenter_Load_ReturnsProductModelWithUrl()
        {
            var context = new Context();
            context.View.Stub(v => v.ProductId).Return("abc");
            context.View.Stub(v => v.CatalogName).Return("def");
            context.Catalog.Stub(c => c.GetProduct("ABC", "def")).Return(new CatalogService.Product { Id = "abc" });

            context.RaiseLoadEvent();

            var product = context.View.Model;
            Assert.AreEqual("~/Product.aspx?id=abc", product.Url);
        }

        [TestMethod]
        public void ProductPresenter_AddToCart_DoesNotAddIfBasketNameEmpty()
        {
            var context = new Context();
            context.Shopping.Stub(s => s.AddToBasket(Guid.Empty, null, null, null, 0, null))
                .IgnoreArguments()
                .Throw(new Exception("Method should not be called."));

            context.RaiseAddToCartEvent(new AddToCartEventArgs("abc", null));
        }

        [TestMethod]
        public void ProductPresenter_AddToCart_DoesAddIfBasketNameNotEmpty()
        {
            var context = new Context();
            var called = false;
            context.Shopping.Stub(s => s.AddToBasket(Guid.Empty, null, null, null, 0, null))
                .IgnoreArguments()
                .WhenCalled(a => called = true);

            context.RaiseAddToCartEvent(new AddToCartEventArgs("abc", "def"));

            Assert.IsTrue(called);
        }

        class Context
        {
            public IProductView View { get; private set; }
            public CatalogService.ICatalogService Catalog { get; private set; }
            public ShoppingService.IShoppingService Shopping { get; private set; }
            public ISessionValueProvider Session { get; private set; }
            public ProductPresenter Presenter {get;private set;}

            public Context()
            {
                View = MockRepository.GenerateStub<IProductView>();
                Catalog = MockRepository.GenerateStub<CatalogService.ICatalogService>();
                Shopping = MockRepository.GenerateStub<ShoppingService.IShoppingService>();
                Session = MockRepository.GenerateStub<ISessionValueProvider>();
                Presenter = new ProductPresenter(View, Catalog, Shopping, Session);
            }

            public void RaiseLoadEvent()
            {
                View.Raise(v => v.Load += null, View, EventArgs.Empty);
            }

            public void RaiseAddToCartEvent(AddToCartEventArgs e)
            {
                View.Raise(v => v.AddToCart += null, View, e);
            }
        }
    }
}
